use std::{sync::Arc, marker::PhantomData, io::{IoSlice, Write, Read, IoSliceMut}};
use  std::ops::Deref;

use super::{XcontainerError, XcontainerResult};

pub struct FixedContainer<T,const C:usize> {
    items:Vec<T>,
    _marker:[PhantomData<T>;C],
}

impl<T,const C:usize> FixedContainer<T,C> {
    pub fn new() -> Self {
        assert!(C<=1024);
        Self {
            items:Vec::new(),
            _marker:[PhantomData;C],
        }
    }
}

impl<T,const C:usize> Deref for FixedContainer<T,C> {
    type Target = Vec<T>;
    fn deref(&self) -> &Self::Target {
        &self.items
    }
}

impl<T:Copy,const C:usize> FixedContainer<T,C> {
    #[inline(always)]
    pub fn append_item(&mut self,items:T) -> XcontainerResult<usize>  {
        let no = self.items.len();
        no
            .eq(&C)
            .then(||{ self.items.push(items); no })
            .ok_or(XcontainerError::FullContainer)
    }

    pub fn borrow_raw(&self) -> &[u8] {
        unsafe { std::mem::transmute::<&[T],&[u8]>(&self.items) }
    }

    pub fn borrow_raw_mut(&mut self) -> &mut [u8] {
        unsafe { std::mem::transmute::<&mut [T],&mut [u8]>(&mut self.items) }
    }


    pub fn on_raw_write<W:Write>(&self,writer:&mut W) -> XcontainerResult<()> {
        writer
            .write(self.borrow_raw())
            .map_err(|e|XcontainerError::FixedContainerWrite(e))?;
        Ok(())
    }

    pub fn on_raw_read<R:Read>(reader:&mut R) -> XcontainerResult<Self> {
        let mut con = Self::new();
        con.items.reserve(C);
        unsafe { con.items.set_len(C); }
        let real_size = reader
            .read(con.borrow_raw_mut())
            .map_err(|e|XcontainerError::FixedContainerWrite(e))?;
        let real_len = real_size / std::mem::size_of::<T>();
        assert!(real_len*std::mem::size_of::<T>() == real_size);
        unsafe { con.items.set_len(real_len); }
        Ok(con)
    }
}

impl<T:FixedContainerWriteItem,const C:usize> FixedContainer<Arc<T>,C> {
    pub fn append_arc_item(&mut self,items:&Arc<T>) -> XcontainerResult<usize>  {
        let no = self.items.len();
        no
            .eq(&C)
            .then(||{ self.items.push(items.clone()); no })
            .ok_or(XcontainerError::FullContainer)
    }

    pub fn on_vec_write<W:Write>(&self,writer:&mut W) -> XcontainerResult<()> {
        let io_vec:Vec<_> = self
            .items
            .iter()
            .map(|t|IoSlice::new(t.as_io_slice()))
            .into_iter()
            .collect();
        writer
            .write_vectored(&io_vec)
            .map_err(|e|XcontainerError::FixedContainerWrite(e))?;
        Ok(())
    }

}

impl<T:FixedContainerReadItem,const C:usize> FixedContainer<Arc<T>,C> {
    pub fn on_vec_read<R:Read>(reader:&mut R) -> XcontainerResult<Self> {
        let mut item_vec = vec![Arc::new(T::uninit());C];
        let mut io_vec:Vec<_> = item_vec
            .iter_mut()
            .map(|t|IoSliceMut::new(Arc::get_mut(t).unwrap().as_io_slice_mut()))
            .into_iter()
            .collect();
        let read_bytes = reader
            .read_vectored(&mut io_vec)
            .map_err(|e|XcontainerError::FixedContainerWrite(e))?;
        assert!(read_bytes!=0);
        let read_item_num = read_bytes / T::SLICE_LEN;
        let rest_bytes = read_bytes - read_item_num * T::SLICE_LEN;
        if rest_bytes != 0 {
            item_vec.resize(read_item_num + 1, Arc::new(T::uninit()));
            Arc::get_mut(&mut item_vec[read_item_num]).expect("REASON").set_bytes(rest_bytes);
        } else {
            item_vec.resize(read_item_num, Arc::new(T::uninit()));
        }
        Ok(Self{
            items:item_vec,
            _marker:[PhantomData;C],
        })
    }
}

pub trait FixedContainerWriteItem {
    fn as_io_slice(&self) -> &[u8];
}

pub trait FixedContainerReadItem {
    const SLICE_LEN:usize;
    fn uninit() -> Self;
    fn set_bytes(&mut self,len:usize);
    fn as_io_slice_mut(&mut self) -> &mut [u8];
}

impl<T:Copy,const C:usize> FixedContainerWriteItem for FixedContainer<T,C> {
    fn as_io_slice(&self) -> &[u8] {
        self.borrow_raw()
    }
}

impl<T:Copy,const C:usize> FixedContainerReadItem for FixedContainer<T,C> {
    const SLICE_LEN:usize = C*std::mem::size_of::<T>();
    fn uninit() -> Self {
        let mut item_vec = Vec::with_capacity(C);
        unsafe { item_vec.set_len(C); }
        Self {
            items:item_vec,
            _marker:[PhantomData;C],
        }
    }

    fn set_bytes(&mut self,bytes:usize) {
        assert!(bytes%std::mem::size_of::<T>() == 0);
        unsafe { self.items.set_len(bytes/std::mem::size_of::<T>()); }
    }

    fn as_io_slice_mut(&mut self) -> &mut [u8] {
        self.borrow_raw_mut()
    }
}